﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using ZoneFiveSoftware.Common.Visuals;
using ZoneFiveSoftware.Common.Visuals.Fitness;
using ZoneFiveSoftware.Common.Data;
using ZoneFiveSoftware.Common.Data.Fitness;
using ZoneFiveSoftware.Common.Visuals.Util;
using ZoneFiveSoftware.Common.Data.Measurement;

using SportTracksSwimSetPlugin.Common;

namespace SportTracksSwimSetPlugin
{

    public partial class SwimSetPage : UserControl, IDetailPage
    {


        public SwimSetPage()
        {
            InitializeComponent();

            treeList1.Columns.Add(new TreeList.Column("Reps",
                "", 40, StringAlignment.Far));
            treeList1.Columns.Add(new TreeList.Column("Distance",
                "", 40, StringAlignment.Near));
            treeList1.Columns.Add(new TreeList.Column("RestTime",
                "", 60, StringAlignment.Near));
        }

        public Guid Id
        {
            get { return new Guid("71c449e0-9679-488e-be97-1ff7445fd1dc"); }
        }

        public bool MenuEnabled
        {
            get {

                IList<IActivity> activities = ViewSelectedActivities;

                if (activities.Count == 1 && (activities[0].Category.ToString().ToLower().StartsWith("swim")))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public IList<string> MenuPath
        {
            get { return null; }
        }

        public bool MenuVisible
        {
            get { return true; }
        }

        public bool PageMaximized
        {
            get { return false; }
            set {  }
        }

        public Control CreatePageControl()
        {
            return this;
        }

        public bool HidePage()
        {
            return true;
        }

        public string PageName
        {
            get { return "Swim Sets"; }
        }

        public void ShowPage(string bookmark)
        {
        }

        public IPageStatus Status
        {
            get { return null; }
        }

        public void ThemeChanged(ITheme visualTheme)
        {
            treeList1.ThemeChanged(visualTheme);
        }

        public string Title
        {
            get { return "Swim Sets"; }
        }

        public void UICultureChanged(System.Globalization.CultureInfo culture)
        {
            foreach (TreeList.Column column in treeList1.Columns)
            {
                switch (column.Id)
                {
                    case "Reps":
                        column.Text = "Reps";
                        break;
                    case "Distance":
                        column.Text = "Dist";
                        break;
                    case "RestTime":
                        column.Text = "Rest";
                        break;
                }
            }

        }

        public IDailyActivityView View
        {
            set { 
                view = value;
                view.SelectionProvider.SelectedItemsChanged += new EventHandler(OnViewSelectedItemsChanged);
            }
        }
        
        public event PropertyChangedEventHandler PropertyChanged;


        private IDailyActivityView view;

        protected IList<IActivity> ViewSelectedActivities
        {
            get
            {
                return CollectionUtils.GetAllContainedItemsOfType<IActivity>
                  (view.SelectionProvider.SelectedItems);
            }
        }

        protected virtual void RefreshPage()
        {
            IList<IActivity> activities = ViewSelectedActivities;
            foreach (IActivity activity in activities)
            {
                System.Diagnostics.Trace.WriteLine("Selected" + activity.ReferenceId);
            }

            if (activities.Count != 1 || (!activities[0].Category.ToString().ToLower().StartsWith("swim")))
            {
                treeList1.Visible = false;
            }
            else
            {
                treeList1.Visible = true;
                treeList1.RowData = parseLaps(activities[0]);
                printDistanceTracks(activities[0]);
            }
         
        }

        protected void OnViewSelectedItemsChanged(object sender, EventArgs e)
        {
            RefreshPage();
        }

        private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e)
        {

        }



        private List<SwimSetRecord> parseLaps(IActivity activity)
        {

            List<SwimSetRecord> returnList = new List<SwimSetRecord> { };
            float swimDistance = 0;
            int restSeconds = 0;
            double swimDistanceUserUnits;
            bool newSet = false;

            if (activity.Laps.Count == 0) return null;
            
            //Log.WriteToLogfile("", false);
           
            // get the units for this activity
            Length.Units units = activity.Category.DistanceUnits;
            Log.WriteToLogfile("Units: " + units.ToString(), Log.LogLevel.DEBUG);

            int repCount = 0;

            for (int lapIdx = 0; lapIdx < activity.Laps.Count; lapIdx += 2)
            {
                int restIdx = lapIdx + 1;
                Log.WriteToLogfile("Lap " + lapIdx.ToString(), Log.LogLevel.DEBUG);
                ILapInfo swimLap = activity.Laps[lapIdx];

                ILapInfo restLap = null;
                if (restIdx < activity.Laps.Count)
                {
                    restLap = activity.Laps[restIdx];
                }


                if ( (swimDistance != swimLap.TotalDistanceMeters) || newSet)
                {
                    newSet = false;
                    // new set, add in the previous set
                    swimDistanceUserUnits = Length.Convert(swimDistance, Length.Units.Meter, units);

                    // add in the set that we just finished collecting
                    if (repCount > 0)
                    {
                        returnList.Add(new SwimSetRecord((long)swimDistanceUserUnits, restSeconds, repCount));
                    }

                    // after the last swim of the workout, the rest lap may not exist
                    if (restLap != null)
                    {
                        // round the rest to the nearest 5"
                        int roundMsec = 0;
                        if (restLap.TotalTime.Milliseconds > 500) 
                            roundMsec = 1;
                        // math to round to nearest 5 secs
                        // could not find a library function to do this
                        int roundedSeconds = ( (restLap.TotalTime.Seconds + roundMsec + 2 ) / 5 ) * 5;
                        restSeconds = restLap.TotalTime.Minutes * 60 + roundedSeconds;
                    }
                    else
                    {
                        restSeconds = 0;
                    }
                    swimDistance = swimLap.TotalDistanceMeters;

                    repCount = 1;
                }
                else
                {
                    // this is potentially another lap within the swim
                    repCount++;

                    // check the rest time to see if it's in range
                    if (restLap != null)
                    {
                        // in the case where the rest lap is off, let one lap make it in
                        // usualy, when you finish a set, you take extra rest, so for the set:
                        // 4x50 10" RI
                        // the rest times could be 8", 10", 12", 60"
                        // and that's fine

                        int roundMsec = 0;
                        if (restLap.TotalTime.Milliseconds > 500)
                            roundMsec = 1;
                        int addtlRestSeconds = restLap.TotalTime.Minutes * 60 + restLap.TotalTime.Seconds;
                        if (restSeconds == ((addtlRestSeconds + roundMsec + 2) / 5) * 5)
                        {
                            // this lap fits in our current set; we'll keep going
                            Log.WriteToLogfile("Rest within current set", Log.LogLevel.DEBUG);
                        }
                        else
                        {
                            // rouding the rest to the nearest 5" doesn't match our current set
                            // since the distance does match the last, let's loosen up a little
                            // We'll consider this still part of the set if the rest rouded to the nearest
                            // 10 equals our current rest interval, the next lap distance is the same
                            // and it's rest rouded to 5" matches

                            // assume it's not going to work
                            newSet = true;

                            int roundedRestSeconds = ( (restSeconds + 5 ) / 10) * 10;
                            if ( roundedRestSeconds == (((addtlRestSeconds + 5) / 10) * 10))
                            {
                                // make sure there is another lap
                                if ((lapIdx + 2) < activity.Laps.Count)
                                {
                                    ILapInfo nextLap = activity.Laps[lapIdx + 2];

                                    ILapInfo nextRestLap = null;
                                    if ((restIdx + 2) < activity.Laps.Count)
                                    {
                                        // the next lap does have a rest period
                                        nextRestLap = activity.Laps[restIdx + 2];
                                    }
                                    else
                                    {
                                        // there is a next lap, but it doesn't have rest (ie workout ended)
                                        // set the restLap to the same as the last good rest lap
                                        nextRestLap = activity.Laps[restIdx - 2];
                                    }


                                    if (swimDistance == nextLap.TotalDistanceMeters)
                                    {
                                        // next lap distance matches our current distance
                                        // we need to see if it fits within 5" of our designated rest
                                        roundMsec = 0;
                                        if (nextRestLap.TotalTime.Milliseconds > 500)
                                            roundMsec = 1;
                                        int nextRestSeconds = nextRestLap.TotalTime.Minutes * 60 + nextRestLap.TotalTime.Seconds;
                                        if (restSeconds == (((nextRestSeconds + roundMsec + 2) / 5) * 5))
                                        {
                                            //we're good
                                            newSet = false;
                                        }
                                    }

                                }
                            }
                        }
                    }
                }
            }
            // add the last set
            swimDistanceUserUnits = Length.Convert(swimDistance, Length.Units.Meter, units);

            returnList.Add(new SwimSetRecord((long)swimDistanceUserUnits, restSeconds, repCount));

            return returnList;
        }

        private void printDistanceTracks(IActivity rawActivity)
        {

            ActivityInfo actInfo = new ActivityInfoCache().GetInfo(rawActivity);

            Log.WriteToLogfile("ActivityInfoCache", Log.LogLevel.DEBUG);
            if (actInfo.HasDistanceData)
            {
                Log.WriteToLogfile("DistanceMeters: " + actInfo.DistanceMeters.ToString(), Log.LogLevel.DEBUG);
                Log.WriteToLogfile("DistanceMetersMoving: " + actInfo.DistanceMetersMoving.ToString(), Log.LogLevel.DEBUG);
                Log.WriteToLogfile("DistanceMetersNonPaused: " + actInfo.DistanceMetersNonPaused.ToString(), Log.LogLevel.DEBUG);
            }

            Log.WriteToLogfile("Raw Data Tracks:", Log.LogLevel.DEBUG);
            if (rawActivity.DistanceMetersTrack != null)
            {
                for (int i = 0; i < rawActivity.DistanceMetersTrack.Count; i++)
                {
                    Log.WriteToLogfile(rawActivity.DistanceMetersTrack[i].ToString(), Log.LogLevel.DEBUG);
                }

            }
        }

        private void treeList1_Load(object sender, EventArgs e)
        {

        }
    }

    public class SwimSetRecord
    {
        public SwimSetRecord(long distance, int restSeconds, int numReps) 
        {
            this.distance = distance;
            this.restTime = restSeconds;
            this.numReps = numReps;
        }

        public string Reps
        {
            get { return numReps + " x"; }
        }

        public string Distance
        {
            get { return distance.ToString(); }
        }

        public string RestTime
        {
            get
            {
                if (restTime != 0)
                {
                    //int restSeconds = 0;
                    //if (restTime.Minutes != 0)
                    //{
                    //    restSeconds = restTime.Minutes * 60 + restTime.Seconds;
                    //}
                    //else
                    //{
                    //    restSeconds = restTime.Seconds;
                    //}
                    //return restStr + string.Format("{0:d2}", restTime.Seconds) + " RI";
                    return restTime.ToString() + "\" RI";
                }
                else
                {
                    return "";
                }
            }
        }

        private long distance = 0;
        private int restTime = 0;
        private int numReps = 0;

    }
  
}
